// test_lidar.cpp

#include <iostream>
#include <string>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <list>

#include <quigon.h>
#include "stk_para.h"
#include "stk_lidar.h"
#include "stk_lidar_io.h"
#include "basic_process.h"
#include "noise_filter.h"
#include "fernald.h"
#include "output_lidarpro.h"

using namespace std;
using namespace quigon;
using namespace boost::posix_time;

int main(int argc, char *argv[])
{
	string start_t, end_t;
	double distance;
	if (argc < 4)
	{
		cout << "usage: test_fernald_priori yyyymmddThhmmss yyyymmddThhmmss distance" << endl;
		cout << "The capital 'T' in the 'iso time string' is optional" << endl;
		exit(0);
	}
	else
	{
		start_t = argv[1];
		end_t = argv[2];
		distance = atof(argv[3]);
	}

	// Check the date_time format, if not iso string, add 'T' into it.
	if (start_t[8] != 'T')
		start_t.insert(8, 1, 'T');
	if (end_t[8] != 'T')
		end_t.insert(8, 1, 'T');

	// Load lidar parameters
	STK_Para para("../settings/stk_lidar_para.txt");

	int max_line_size = para.distance_i[distance] + 1;

	// Load proper temperature and pressure "profiles"
	// to calculate backscatter coefficient of atmosphere molecules: beta_m
	Atmos_Profile p_prof = load_atmos_profile("../settings/atmos_profiles/US_1976.p_profile", para);
	Atmos_Profile t_prof = load_atmos_profile("../settings/atmos_profiles/US_1976.t_profile", para);
	Atmos_Profile beta_m = cal_beta_m(t_prof, p_prof, 523.0, 0.0284);

	// Loading the priori data
//	cout << "Loading priori data..." << endl;
//	Time_Serie fe_distance("../settings/lidar/stk_priori_distance.txt");
//	Time_Serie fe_value("../settings/lidar/stk_priori_value.txt");

	// Making a container for the data
	list<STK_Line> container;

	// import the data.
	cout << "Importing data..." << endl;
	import(
	        container,
	        from_iso_string(start_t),		// boost::posix_time::from_iso_string
	        from_iso_string(end_t),		// take care of the "T" in the string
	        para
	);

	cout << "lines num: " << container.size() << endl;

	cout << "Making an averager" << endl;
	Average_Machine<STK_Line> aver(60, stk_aver_attr);
	// Make a functor for correction, and more options are available
	// e.g. Correction<STK_Line> my_corr(para, Status::BACKGROUND | Status::AFTERPULSE | Status::DISTANCE);
	// default is doing every possible correction
	cout << "Making a corrector" << endl;
	Correction<STK_Line, STK_Para> corr(para, Status::NORMALIZE | Status::ENERGY, false);

	// Make a functor for filling the lowest unseen area.
	// here 5 means use the average of lowest 5 known data to fill the unknown area.
	cout << "Making a filler" << endl;
	Fill_Lowest filler(para, 5);

	// Make a filter
	cout << "Making a filter ..." << endl;
	Serie<string, double> filter_para("../settings/lidar/stk_filter.txt");
	Noise_Filter_Proto filter(
	        filter_para["low_index"],
	        filter_para["high_index"],
	        filter_para["low_buddy_num"],
	        filter_para["high_buddy_num"],
	        para.zero_meter_index,
	        para.size - 1);
	double trigger_value = filter_para["trigger_value"];
	size_t lowest_trigger_index = filter_para["lowest_trigger_index"];

	// Make a functor for extinction retrieval
	// here 6.0 means only calculate to 6.0 km away, to save time.
	cout << "Making a retriever" << endl;
	Fernald<STK_Line, STK_Para> fernald(para, beta_m, distance, -999.9, -999.9, true);

	// On output
	string output_file_name = string("../output/stk_") + start_t + "_" + end_t + ".extinctn.txt";
	string::iterator str_iter =
	        remove(output_file_name.begin(), output_file_name.end(), 'T');
	output_file_name.erase(str_iter, output_file_name.end());

	ofstream file(output_file_name.c_str());
	if (!file)
	{
		func_err("Cannot open file to write", output_file_name);
		return 1;
	}

	Output_Lidarpro printer(file, para.zero_meter_index);

	aver(container);
	for (list<STK_Line>::iterator i = container.begin();
	     i != container.end();
	     ++i)
	{
//		cout << "######################################" << endl;
//		print_line_brief(*i);

//		cout << "--------------------------------------" << endl;
		corr(*i);
		filler(*i);
		filter(*i, trigger_value, lowest_trigger_index);
		kick_minus(*i);
//		print_line_brief(*i);

//		cout << "--------------------------------------" << endl;
		fernald(*i);
//		print_line_brief(*i);
	}

	// fill time gaps.
	cout << "Filling time gap..." << endl;
	fill_time_gap(container, 60);

	cout << "Outputing to file: " << output_file_name << endl;
	for (list<STK_Line>::iterator i = container.begin();
	     i != container.end();
	     ++i)
	{
		printer(*i);
	}

	return 0;
}

